﻿#region Copyright (c) 2013-04, Olaf Kober <amarok.projects@gmail.com>
//================================================================================
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//================================================================================
#endregion

#if TESTS

using System;
using System.Threading;
using NUnit.Framework;


namespace Amarok.Agents
{
	public partial class Test_Agent
	{
		#region Post(Message)

		[Test]
		public void Test_Post()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			agent.TestPost(message);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.Null);
		}

		[Test]
		public void Test_Post_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPost(null);
				});
		}

		#endregion

		#region Post(Object, Message)

		[Test]
		public void Test_Post_Label()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			message.Label = "BLAH";
			agent.TestPost("COM1", message);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.EqualTo("COM1"));
		}

		[Test]
		public void Test_Post_Label_NullLabel()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPost(null, new TestMessage());
				});
		}

		[Test]
		public void Test_Post_Label_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPost("BLAH", null);
				});
		}

		#endregion


		#region PostAfter(TimeSpan, Message)

		[Test]
		public void Test_PostAfter_TimeSpan()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			agent.TestPostAfter(TimeSpan.FromMilliseconds(10), message);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.Null);
		}

		[Test]
		public void Test_PostAfter_TimeSpan_NegativeDelay()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(-10), new TestMessage());
				});
		}

		[Test]
		public void Test_PostAfter_TimeSpan_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(10), null);
				});
		}

		#endregion

		#region PostAfter(Int32, Message)

		[Test]
		public void Test_PostAfter_Int32()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			agent.TestPostAfter(10, message);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.Null);
		}

		[Test]
		public void Test_PostAfter_Int32_NegativeDelay()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					agent.TestPostAfter(-10, new TestMessage());
				});
		}

		[Test]
		public void Test_PostAfter_Int32_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(10, null);
				});
		}

		#endregion

		#region PostAfter(TimeSpan, Message, CancellationToken)

		[Test]
		public void Test_PostAfter_TimeSpan_CancellationToken()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			agent.TestPostAfter(TimeSpan.FromMilliseconds(10), message, source.Token);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.Null);
		}

		[Test]
		public void Test_PostAfter_TimeSpan_CancellationToken_NegativeDelay()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(-10), new TestMessage(), source.Token);
				});
		}

		[Test]
		public void Test_PostAfter_TimeSpan_CancellationToken_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(10), null, source.Token);
				});
		}

		#endregion

		#region PostAfter(Int32, Message, CancellationToken)

		[Test]
		public void Test_PostAfter_Int32_CancellationToken()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			agent.TestPostAfter(10, message, source.Token);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.Null);
		}

		[Test]
		public void Test_PostAfter_Int32_CancellationToken_NegativeDelay()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					agent.TestPostAfter(-10, new TestMessage(), source.Token);
				});
		}

		[Test]
		public void Test_PostAfter_Int32_CancellationToken_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(10, null, source.Token);
				});
		}

		#endregion


		#region PostAfter(TimeSpan, Object, Message)

		[Test]
		public void Test_PostAfter_TimeSpan_Label()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			message.Label = "ABC";
			agent.TestPostAfter(TimeSpan.FromMilliseconds(10), "BLAH", message);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.EqualTo("BLAH"));
		}

		[Test]
		public void Test_PostAfter_TimeSpan_Label_NegativeDelay()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(-10), "BLAH", new TestMessage());
				});
		}

		[Test]
		public void Test_PostAfter_TimeSpan_Label_NullLabel()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(10), null, new TestMessage());
				});
		}

		[Test]
		public void Test_PostAfter_TimeSpan_Label_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(10), "BLAH", null);
				});
		}

		#endregion

		#region PostAfter(Int32, Object, Message)

		[Test]
		public void Test_PostAfter_Int32_Label()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			message.Label = "ABC";
			agent.TestPostAfter(10, "BLAH", message);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.EqualTo("BLAH"));
		}

		[Test]
		public void Test_PostAfter_Int32_Label_NegativeDelay()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					agent.TestPostAfter(-10, "BLAH", new TestMessage());
				});
		}

		[Test]
		public void Test_PostAfter_Int32_Label_NullLabel()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(10, null, new TestMessage());
				});
		}

		[Test]
		public void Test_PostAfter_Int32_Label_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(10, "BLAH", null);
				});
		}

		#endregion

		#region PostAfter(TimeSpan, Object, Message, CancellationToken)

		[Test]
		public void Test_PostAfter_TimeSpan_Label_CancellationToken()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			message.Label = "ABC";
			agent.TestPostAfter(TimeSpan.FromMilliseconds(10), "BLAH", message, source.Token);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.EqualTo("BLAH"));
		}

		[Test]
		public void Test_PostAfter_TimeSpan_Label_CancellationToken_NegativeDelay()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(-10), "BLAH", new TestMessage(), source.Token);
				});
		}

		[Test]
		public void Test_PostAfter_TimeSpan_Label_CancellationToken_NullLabel()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(10), null, new TestMessage(), source.Token);
				});
		}

		[Test]
		public void Test_PostAfter_TimeSpan_Label_CancellationToken_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(TimeSpan.FromMilliseconds(10), "BLAH", null, source.Token);
				});
		}

		#endregion

		#region PostAfter(Int32, Object, Message, CancellationToken)

		[Test]
		public void Test_PostAfter_Int32_Label_CancellationToken()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(0));

			var message = new TestMessage();
			message.Label = "ABC";
			agent.TestPostAfter(10, "BLAH", message, source.Token);

			Helper.WaitForCondition(5000, 10, () => agent.MessageHandlerCalled == 1);
			Assert.That(agent.MessageHandlerCalled, Is.EqualTo(1));
			Assert.That(message.Label, Is.EqualTo("BLAH"));
		}

		[Test]
		public void Test_PostAfter_Int32_Label_CancellationToken_NegativeDelay()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					agent.TestPostAfter(-10, "BLAH", new TestMessage(), source.Token);
				});
		}

		[Test]
		public void Test_PostAfter_Int32_Label_CancellationToken_NullLabel()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(10, null, new TestMessage(), source.Token);
				});
		}

		[Test]
		public void Test_PostAfter_Int32_Label_CancellationToken_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);
			var source = new CancellationTokenSource();

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostAfter(10, "BLAH", null, source.Token);
				});
		}

		#endregion


		#region PostOperation(Operation)

		[Test]
		public void Test_PostOperation()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.OperationHandlerCalled, Is.EqualTo(0));

			var progressValue = 0;
			var progressSignal = new ManualResetEvent(false);

			var operation = new TestOperation();
			agent.TestPostOperation(operation,
				p =>
				{
					progressValue = p;
					progressSignal.Set();
				})
				.Wait(5000);

			Assert.That(agent.OperationHandlerCalled, Is.EqualTo(1));
			Assert.That(progressSignal.WaitOne(5000), Is.True);
			Assert.That(progressValue, Is.EqualTo(25));
			Assert.That(operation.Completion.Result, Is.EqualTo("finished"));
			Assert.That(operation.Label, Is.Null);
		}

		[Test]
		public void Test_PostOperation_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostOperation<String, Int32>(null, null);
				});
		}

		#endregion

		#region PostOperation(Operation, CancellationToken)

		[Test]
		public void Test_PostOperation_CancellationToken()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.OperationHandlerCalled, Is.EqualTo(0));

			var progressValue = 0;
			var progressSignal = new ManualResetEvent(false);
			var cancelSource = new CancellationTokenSource();

			var operation = new TestOperation();
			agent.TestPostOperation(
				operation,
				cancelSource.Token,
				p =>
				{
					progressValue = p;
					progressSignal.Set();
				})
				.Wait(5000);

			Assert.That(agent.OperationHandlerCalled, Is.EqualTo(1));
			Assert.That(progressSignal.WaitOne(5000), Is.True);
			Assert.That(progressValue, Is.EqualTo(25));
			Assert.That(operation.Completion.Result, Is.EqualTo("finished"));
			Assert.That(operation.Label, Is.Null);

			Assert.That(operation.CancellationToken.IsCancellationRequested, Is.False);
			cancelSource.Cancel();
			Assert.That(operation.CancellationToken.IsCancellationRequested, Is.True);
		}

		#endregion

		#region PostOperation(Object, Operation)

		[Test]
		public void Test_PostOperation_Label()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.OperationHandlerCalled, Is.EqualTo(0));

			var progressValue = 0;
			var progressSignal = new ManualResetEvent(false);

			var operation = new TestOperation();
			operation.Label = "BLAH";

			agent.TestPostOperation("COM1", operation,
				p =>
				{
					progressValue = p;
					progressSignal.Set();
				})
				.Wait(5000);

			Assert.That(agent.OperationHandlerCalled, Is.EqualTo(1));
			Assert.That(progressSignal.WaitOne(5000), Is.True);
			Assert.That(progressValue, Is.EqualTo(25));
			Assert.That(operation.Completion.Result, Is.EqualTo("finished"));
			Assert.That(operation.Label, Is.EqualTo("COM1"));
		}

		[Test]
		public void Test_PostOperation_Label_NullLabel()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostOperation<String, Int32>(null, new TestOperation(), null);
				});
		}

		[Test]
		public void Test_PostOperation_Label_NullMessage()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.Throws<ArgumentNullException>(() =>
				{
					agent.TestPostOperation<String, Int32>("BLAH", null, null);
				});
		}

		#endregion

		#region PostOperation(Object, Operation, CancellationToken)

		[Test]
		public void Test_PostOperation_Label_CancellationToken()
		{
			var environment = new MyAgentEnvironment();
			var options = new MyAgentOptions();
			var agent = new MyAgent(environment, options);

			Assert.That(agent.OperationHandlerCalled, Is.EqualTo(0));

			var progressValue = 0;
			var progressSignal = new ManualResetEvent(false);
			var cancelSource = new CancellationTokenSource();

			var operation = new TestOperation();
			operation.Label = "BLAH";

			agent.TestPostOperation(
				"COM1",
				operation,
				cancelSource.Token,
				p =>
				{
					progressValue = p;
					progressSignal.Set();
				})
				.Wait(5000);

			Assert.That(agent.OperationHandlerCalled, Is.EqualTo(1));
			Assert.That(progressSignal.WaitOne(5000), Is.True);
			Assert.That(progressValue, Is.EqualTo(25));
			Assert.That(operation.Completion.Result, Is.EqualTo("finished"));
			Assert.That(operation.Label, Is.EqualTo("COM1"));

			Assert.That(operation.CancellationToken.IsCancellationRequested, Is.False);
			cancelSource.Cancel();
			Assert.That(operation.CancellationToken.IsCancellationRequested, Is.True);
		}

		#endregion

	}
}

#endif
